package util.core;

import android.content.Context;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;

/**
 * The Periodic class provides access to the periodic table via the included xml data.
 */
public class Periodic {

    /**
     * This hashmap contains the periodic table with the keys being atomic symbols.
     */
    public static HashMap<String, Atom> elements;
    public static ArrayList<String> elementSymbols;
    public static ArrayList<String> elementNames;
    public static ArrayList<Integer> numbers;
    public static ArrayList<Double> masses;

    public static int status;

    /**
     * This method initializes of the global variables which we will be using by reading in a xml file.
     * In the future, there will be polyatomic ions
     */
    public static void initialize() {
        try {
            createLists();
            BufferedInputStream file;
            try {
                file = new BufferedInputStream(new FileInputStream(new File("trunk//util//core//periodic_table.xml")), 8000);
            } catch (Exception e) {
                file = new BufferedInputStream(new FileInputStream(new File("src//util//core//periodic_table.xml")), 8000);
            }
            //Both project setups should work now.
            DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
            Document doc = db.parse(file);
            NodeList nodeLst = doc.getElementsByTagName("ATOM");
            getElements(nodeLst);
            sort(false);
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(0);
        }

    }

    public static void initialize(final Context context) {
        new Thread() {
            public void run() {
                try {
                    if (elements == null) {
                        createLists();
                        BufferedInputStream file = null;
                        try {
                            file = new BufferedInputStream(context.getResources().getAssets().open("periodic_table.xml"), 8000);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        if (file != null) {
                            status++;
                            DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
                            Document doc = db.parse(file);
                            NodeList nodeLst = doc.getElementsByTagName("ATOM");
                            getElements(nodeLst);
                            sort(true);

                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    System.exit(0);
                }
            }


        }.start();


    }

    private static void createLists() {
        elements = new HashMap<String, Atom>();
        elementSymbols = new ArrayList<String>();
        elementNames = new ArrayList<String>();
        numbers = new ArrayList<Integer>(112);
        for (int i = 1; i < 113; i++) {
            numbers.add(i);
        }
        masses = new ArrayList<Double>(112);
    }

    private static void sort(boolean full) {
        Collections.sort(elementSymbols);
        if (full) {
            Collections.sort(elementNames);
            Collections.sort(masses);
        }
    }

    public static Atom findByName(String name) {
        for (Atom c : elements.values())
            if (c.getName().equalsIgnoreCase(name))
                return c;
        return null;
    }

    public static Atom findByMass(Double mass) {
        for (Atom c : elements.values())
            if (c.getAtomicWeight() == mass)
                return c;
        return null;
    }

    public static Atom findByNumber(int number) {
        for (Atom c : elements.values())
            if (c.getAtomicNumber() == number)
                return c;
        return null;
    }


    /**
     * Puts each element into a hash map, with their symbols as the key
     *
     * @param nodeLst The list of nodes from= the xml file.
     */
    private static void getElements(NodeList nodeLst) {
        Node fstNode;
        for (int s = 0; s < nodeLst.getLength(); s++) {
            fstNode = nodeLst.item(s);
            if (fstNode.getNodeType() == Node.ELEMENT_NODE) {
                Atom k = new Atom(fstNode);
                elements.put(k.getSymbol(), k);
                elementSymbols.add(k.getSymbol());
                elementNames.add(k.getName());
                masses.add(k.getAtomicWeight());
                status++;
            }
        }
    }

    public static ArrayList<String> getElementNamesWith(String start) {
        boolean added = false;
        ArrayList<String> result = new ArrayList<String>();
        for (String c : elementSymbols) {
            if (c.startsWith(start)) {
                if (!added)
                    added = true;
                result.add(c);
            } else if (added)
                break;
        }
        return result;
    }
}
